Redis的安装


1. Redis 的下载

  • 下载网址

https://github.com/microsoftarchive/redis/releases


2. Redis 的安装






3. 启动 Redis 服务端软件

  • 服务端软件的作用: 解析客户端发送过来的指令对内存中写入或读取缓存数据

  • 找到 Redis 的安装目录然后执行 redis-server.exe 启动 Redis


4. Redis 的客户端软件 -> redis-cli.exe

  • 客户端软件的作用: 向服务端发送指令,从而对缓存数据进行操作

  • redis-cli.exe 用于设置缓存



Redis的介绍


1. 为什么要使用缓存

在Django中,当用户请求到达视图后,视图会先从数据库提取数据放到模板中进行动态渲染,渲染后的结果就是用户看到的网页。如果用户每次请求都从数据库提取数据并渲染,将极大降低性能,不仅服务器压力大,而且客户端也无法即时获得响应。如果能将渲染后的结果放到速度更快的缓存中,每次有请求过来,先检查缓存中是否有对应的资源,如果有,直接从缓存中取出来返回响应,节省取数据和渲染的时间,不仅能大大提高系统性能,还能提高用户体验

2. Redis 的介绍

  • Redis 就是一个软件 和 Mysql 类似,都是用于存储数据

  • Redis 是一个非关系型数据库(即: 以键值对的形式存储数据)

  • Redis 所存储的都是字符串,不能储存数字(就算在开发的时候value所填写的是数字,那么 redis 模块也会将数字转换为字符串再进行存储)

  • Redis 可以被多台机器连接,然后操作缓存中的数据(和Mysql一样可以被别的机器连接)

3. Redis 和 MySQL 的区别

  • MySQL是一个软件,帮助开发者对一台机器的硬盘进行操作

  • Redis是一个软件,帮助开发者对一台机器的内存进行操作

4. 使用 Redis 的好处

  • 速度快,提高效率,因为 Redis 的数据是存放在内存中的,而Mysql是存放在磁盘中的(因为使用Mysql的时候,需用进行打开读写操作,所以要比 Redis 直接从内存中获取数据要慢)

  • 支持丰富的数据类型: string(字符串),list(列表),set(集合),sorted set(有序集合),hash(字典)

  • 支持事务,操作都是原子性,所谓的原子性就是对数据的更改要么全部执行,要么全部不执行

  • 丰富的特性:可用于缓存,消息,按key设置过期时间,过期后将会自动删除

5. 使用 Redis 的缺点

  • 服务器一旦崩溃,储存在内存中的缓存数据就会没有

6. Redis 相比 Memcached有哪些优势

  • (Memcached的说明: Memcached 的功能和 redis 是一样的,用于缓存数据)

  • Memcached 所有的值均是简单的字符串,redis作为其替代者,支持更为丰富的数据类型

  • redis的速度比Memcached快很多

  • redis可以持久化其数据 -> 将数据保存到磁盘上

7. redis 和 Memcached 的区别

  • 存储方式

    • Memecache 把数据全部存在内存之中,断电后会全部丢失,数据不能超过内存大小

    • Redis有部份存在硬盘上,这样能保证数据的持久性

  • 数据类型

    • Memecache 只支持简单的字符串

    • Redis 支持丰富的数据类型: string(字符串),list(列表),set(集合),sorted set(有序集合),hash(字典)

  • 存储空间的大小

    • Memecache 最大只有 1M

    • Redis 最大可以达到 1G

8. redis 的使用场景

  • 通俗理解: 临时状态,且频繁修改状态,如: 购物车

  • 会话缓存(Session Cache

    • 最常用的一种使用Redis的情景是会话缓存(session cache)。用Redis缓存会话比其他存储(如Memcached)的优势在于:Redis提供持久化。当维护一个不是严格要求一致性的缓存时,如果用户的购物车信息全部丢失,大部分人都会不高兴的,现在,他们还会这样吗?幸运的是,随着 Redis 这些年的改进,很容易找到怎么恰当的使用Redis来缓存会话的文档。甚至广为人知的商业平台Magento也提供Redis的插件

  • 全页缓存(FPC)

    • 除基本的会话token之外,Redis还提供很简便的FPC平台。回到一致性问题,即使重启了Redis实例,因为有磁盘的持久化,用户也不会看到页面加载速度的下降,这是一个极大改进,类似PHP本地FPC。再次以Magento为例,Magento提供一个插件来使用Redis作为全页缓存后端。此外,对WordPress的用户来说,Pantheon有一个非常好的插件 wp-redis,这个插件能帮助你以最快速度加载你曾浏览过的页面。

  • 队列

    • Reids在内存存储引擎领域的一大优点是提供 list 和 set 操作,这使得Redis能作为一个很好的消息队列平台来使用。Redis作为队列使用的操作,就类似于本地程序语言(如Python)对 list 的 push/pop 操作

    • 如果你快速的在Google中搜索“Redis queues”,你马上就能找到大量的开源项目,这些项目的目的就是利用Redis创建非常好的后端工具,以满足各种队列需求。例如,Celery有一个后台就是使用Redis作为broker,你可以从这里去查看

  • 排行榜/计数器

    • Redis在内存中对数字进行递增或递减的操作实现的非常好。集合(Set)和有序集合(Sorted Set)也使得我们在执行这些操作的时候变的非常简单,Redis只是正好提供了这两种数据结构。所以,我们要从排序集合中获取到排名最靠前的10个用户–我们称之为“user_scores”,我们只需要像下面一样执行即可:

    • 当然,这是假定你是根据你用户的分数做递增的排序。如果你想返回用户及用户的分数,你需要这样执行:

      • ZRANGE user_scores 0 10 WITHSCORES
      • Agora Games就是一个很好的例子,用Ruby实现的,它的排行榜就是使用Redis来存储数据的,你可以在这里看到

  • 发布/订阅

    • 发布/订阅的使用场景确实非常多。我已看见人们在社交网络连接中使用,还可作为基于发布/订阅的脚本触发器,甚至用Redis的发布/订阅功能来建立聊天系统!(不,这是真的,你可以去核实)

Python 安装 Redis


pip3 install redis -i https://pypi.douban.com/simple  # 使用豆瓣的镜像

  • 安装 redis 最好同时安装上 hiredis

  • hiredis 的作用: 提升 redis 的使用性能

  • 如果已经安装了hiredis模块,redis 默认会尝试使用HiredisParser,否则会使用PythonParser

pip3 install hiredis -i https://pypi.douban.com/simple  # 使用豆瓣的镜像

连接 Redis Server


1. 方式一

  • redis.Redis(host='ip地址', port=端口号, password='密码')

    • 如果 host 和 port 不传,默认使用本地的ip和端口

    • 如果没有密码可以不用填写 password 参数

# 固定写法

import redis

r = redis.Redis(host='ip地址', port=端口号,password='密码') 

r = redis.Redis()  # 如果 host 和 port 不传,默认使用本地的ip和端口

# 使用 r 对象操作缓存中的数据

import redis

r = redis.Redis(host='10.211.55.4', port=6379, password='123')

# r = redis.Redis()  # 如果 host 和 port 不传,默认使用本地的ip和端口

# 使用 r 对象操作缓存中的数据

  • decode_responses 参数

    • decode_responses 参数默认值 Flase

    • decode_responses 参数 -> 是否自动进行解码,因为从缓存中获取到的值是 Bytes 类型的需要手动进行解码,当 decode_responses=True 的时候,在获取缓存中的值的时候会自动进行解码

import redis

r = redis.Redis(host='10.211.55.4', port=6379, password='123', decode_responses=True)

# r = redis.Redis(decode_responses=True)

2. 方式二

  • 连接池 -> 推荐使用

  • 连接池: 避免每次建立、释放连接的开销。默认,每个Redis实例都会维护一个自己的连接池。可以直接建立一个连接池,然后作为参数Redis,这样就可以实现多个Redis实例共享一个连接池

  • 注意: 连接池只创建一次,使用模块的单例模式方式创建连接池,避免在导入模块的时候重复创建连接池,如果每一次使用redis都创建一个连接池,那么性能就会和方式一一样

  • 固定写法

# redis_pool.py

import redis

# 创建连接池
POOL = redis.ConnectionPool(host='ip地址', port=端口号, password='密码', max_connections=最大连接数 # 注意: 连接池只创建一次,使用模块的单例模式方式创建连接池,避免在导入模块的时候重复创建连接池
POOL = redis.ConnectionPool()  # 如果 host 和 port 不传,默认使用本地的ip和端口
                                 # 如果没有密码可以不用填写 password 参数
                                 # 如果 max_connections 不传,默认使用redis连接池的最大连接数

# xxx.py

import redis
from redis_pool import POOL

# 去连接池中获取连接
r = redis.Redis(connection_pool=POOL)

# 使用 r 对象操作缓存中的数据

  • 实例

# redis_pool.py

import redis

# 创建连接池
POOL = redis.ConnectionPool(host='10.211.55.4', port=6379, password='123', max_connections=1000)  # 注意: 连接池只创建一次,使用模块的单例模式方式创建连接池,避免在导入模块的时候重复创建连接池
# POOL = redis.ConnectionPool()  # 如果 host 和 port 不传,默认使用本地的ip和端口
# 如果没有密码可以不用填写 password 参数
                                 # 如果 max_connections 不传,默认使用redis连接池的最大连接数

# xxx.py

import redis
from redis_pool import POOL

# 去连接池中获取连接
r = redis.Redis(connection_pool=POOL)

# 使用 r 对象操作缓存中的数据

  • decode_responses 参数

    • decode_responses 参数默认值 Flase

    • decode_responses 参数 -> 是否自动进行解码,因为从缓存中获取到的值是 Bytes 类型的需要手动进行解码,当 decode_responses=True 的时候,在获取缓存中的值的时候会自动进行解码

# redis_pool.py

import redis

# 创建连接池
POOL = redis.ConnectionPool(host='10.211.55.4', port=6379, password='123', max_connections=1000, decode_responses=True)  # 注意: 连接池只创建一次,使用模块的单例模式方式创建连接池,避免在导入模块的时候重复创建连接池
# POOL = redis.ConnectionPool(decode_responses=True)

# xxx.py

import redis
from redis_pool import POOL

r = redis.Redis(connection_pool=POOL)

Redis 的使用


注意: 连接池一定要使用模块的单例模式方式创建,否则性能方面和上面的方式一的性能是一样的,这里只是为了方便才写在一块的

# 日常开发的时候连接池一定要使用模块的单例模式方式创建,在这里只是为了方便笔记才写在一块的

import redis

pool = redis.ConnectionPool(decode_responses=True)
r = redis.Redis(connection_pool=pool)

1. String(字符串)类型的操作


  • set(name, value, ex=None, px=None, nx=False, xx=False)

    • 添加或修改缓存(包含过期时间)

    • 参数:
      • name: 缓存名
      • value: 需要缓存的字符串类型的值
      • ex: 过期时间(秒)
      • px: 过期时间(毫秒)
      • nx: 如果值为 True,当 name 不存在的时候,当前set操作才会执行
      • xx: 如果值为 True,当 name 存在的时候,当前set操作才会执行

import redis

pool = redis.ConnectionPool(decode_responses=True)
r = redis.Redis(connection_pool=pool)

r.set(name='username', value='Kevin', ex=5)

  • setnx(name, value) 

    • 添加缓存(不包含过期时间)

    • 只有 name 不存在时,才添加 value 等于字符串类型的缓存

import redis

pool = redis.ConnectionPool(decode_responses=True)
r = redis.Redis(connection_pool=pool)

r.setnx(name='username', value='Kevin')

  • setex(name, value, time)

    • 添加或修改过期时间单位为秒的缓存(包含过期时间)

    • 参数:
      • name: 缓存名
      • value: 需要缓存的字符串类型的值
      • time: 过期时间(数字秒 或 timedelta对象)

import redis

pool = redis.ConnectionPool(decode_responses=True)
r = redis.Redis(connection_pool=pool)

r.setex(name='username', value='Kevin', time=5)

  • psetex(name, time_ms, value)

    • 添加或修改过期时间单位为毫秒缓存(包含过期时间)

    • 参数:
      • name: 缓存名
      • value: 需要缓存的字符串类型的值
      • time_ms: 过期时间(数字毫秒 或 timedelta对象)

import redis

pool = redis.ConnectionPool(decode_responses=True)
r = redis.Redis(connection_pool=pool)

r.psetex(name='username', value='Kevin', time_ms=5000)

  • mset(mapping)

    • 批量设置缓存不包含过期时间

    • 参数:
      • mapping: 字典,如:{'k1':'v1', 'k2': 'v2'}

import redis

pool = redis.ConnectionPool(decode_responses=True)
r = redis.Redis(connection_pool=pool)

r.mset({'k1': 'v1', 'k2': 'v2'})

  • msetnx(mapping)

    • 批量设置缓存不包含过期时间),如果该缓存存在则不进行添加

    • 参数:
      • mapping: 字典,如:{'k1':'v1', 'k2': 'v2'}

import redis

pool = redis.ConnectionPool(decode_responses=True)
r = redis.Redis(connection_pool=pool)

r.msetnx({'k1': 'v3', 'k2': 'v4'})

  • get(name)

    • 获取缓存中的值,且 value 的类型为 String(字符串)

    • 当 decode_responses=False/decode_responses参数没有设置 的时候获取到的值是 bytes 类型

import redis

pool = redis.ConnectionPool()
r = redis.Redis(connection_pool=pool)

username = r.get('username')

print(username)  # b'Kevin'

    • 当 decode_responses=True 的时候获取到的值是经过解码后的值(即: 字符串类型)

import redis

pool = redis.ConnectionPool(decode_responses=True)
r = redis.Redis(connection_pool=pool)

username = r.get('username')

print(username)  # Kevin

  • mget(keys, *args)

    • 批量获取缓存中的值,且 value 的类型为 String(字符串)

    • decode_responses 参数的问题和 get(name) 方法一样(这里就不做演示了)

    • 写法一

import redis

pool = redis.ConnectionPool(decode_responses=True)
r = redis.Redis(connection_pool=pool)

r_value_list = r.mget(['k1', 'k2'])

print(r_value_list)  # ['v1', 'v2']

    • 写法二

import redis

pool = redis.ConnectionPool(decode_responses=True)
r = redis.Redis(connection_pool=pool)

r_value_list = r.mget('k1', 'k2')

print(r_value_list)  # ['v1', 'v2']

  • getset(name, value)

    • 设置新值并返回原来的值

    • decode_responses 参数的问题和 get(name) 方法一样(这里就不做演示了)

import redis

pool = redis.ConnectionPool(decode_responses=True)
r = redis.Redis(connection_pool=pool)

old_value = r.getset(name='username', value='Yeung')

print(old_value)  # Kevin

  • getrange(key, start, end)

    • 切片

    • decode_responses 参数的问题和 get(name) 方法一样(这里就不做演示了)

    • 参数:
      • key: 缓存中key的名字
      • start: 切片起始值
      • end: 切片结束值

import redis

pool = redis.ConnectionPool(decode_responses=True)
r = redis.Redis(connection_pool=pool)

result = r.getrange(key='username', start=0, end=1)

print(result)  # 原本的值: Kevin,切片后得到的值: Ke

  • setrange(name, offset, value)

    • 修改字符串内容,从指定字符串索引开始向后替换(新值太长时,则向后添加)

    • 参数: 
      • name: 缓存名
      • offset: 字符串的索引,字节(一个汉字3个字节)
      • value: 需要插入的值

import redis

pool = redis.ConnectionPool(decode_responses=True)
r = redis.Redis(connection_pool=pool)

r.setrange(name='username', offset=2, value='_插入的值_')

print(r.get('username'))  # 原本的值: Kevin,插值后: Ke_插入的值_

  • strlen(name)

    • 返回name对应缓存的值的字节长度(一个汉字3个字节)

import redis

pool = redis.ConnectionPool(decode_responses=True)
r = redis.Redis(connection_pool=pool)

english_length = r.strlen('username')
print(english_length)  # 值: Kevin,长度: 5

chinese_length = r.strlen('chinese')
print(chinese_length)  # 值: 中文,长度: 6

  • incr(name, amount)

    • 整数自增,当name不存在时,则创建name=amount,否则,进行整数自增

    • 需要自增的value必须是整数

    • 参数: 
      • name: 缓存名
      • amount: 每次自增的数量(即: 每次添加的数量),必须是整数

import redis

pool = redis.ConnectionPool(decode_responses=True)
r = redis.Redis(connection_pool=pool)

r.incr(name='age', amount=2)

print(r.get('age'))  # 原本的值: 1,自增后的值: 3

  • incrbyfloat(name, amount)

    • 浮点数自增,当name不存在时,则创建name=amount,否则,进行浮点数自增

    • 需要自增的value可以是整数或浮点数

    • 参数:
      • name: 缓存名
      • amount: 每次自增的数量(即: 每次添加的数量),可以是整数或浮点数

import redis

pool = redis.ConnectionPool(decode_responses=True)
r = redis.Redis(connection_pool=pool)

r.incrbyfloat(name='age', amount=2.5)

print(r.get('age'))  # 原本的值: 1,自增后的值: 3.5

  • decr(name, amount=1)

    • 整数自减,当name不存在时,则创建name=amount,否则,进行整数自减

    • 需要自减的value必须是整数

    • 参数:
      • name: 缓存名
      • amount: 每次自减的数量(即: 每次减少的数量),必须是整数

import redis

pool = redis.ConnectionPool(decode_responses=True)
r = redis.Redis(connection_pool=pool)

r.decr(name='age', amount=2)

print(r.get('age'))  # 原本的值: 2,自增后的值: 0

  • append(key, value)

    • 在指定的缓存值后面追加内容

    • 参数
      • key: 缓存中key的名字
      • value: 需要追加的内容

import redis

pool = redis.ConnectionPool(decode_responses=True)
r = redis.Redis(connection_pool=pool)

r.append(key='username', value='追加的内容')

print(r.get('username'))  # 原本的值: Kevin,追加内容后的值: Kevin追加的内容

2. List(列表)类型的操作


  • lpush(name, *values)

    • 在name对应的list中添加元素,每个新的元素都添加到列表的最左边 -> 相当于创建一个列表

    • 参数:
      • name: 缓存名
      • values: 要添加的元素,可以接收多个值

    • 写法一

import redis

pool = redis.ConnectionPool(decode_responses=True)
r = redis.Redis(connection_pool=pool)

r.lpush('books', '三国演义', '红楼梦', '西游记', '水浒传')

print(r.lrange('books', 0, -1))  # ['水浒传', '西游记', '红楼梦', '三国演义']

    • 写法二

import redis

pool = redis.ConnectionPool(decode_responses=True)
r = redis.Redis(connection_pool=pool)

books = ['三国演义', '红楼梦', '西游记', '水浒传']
r.lpush('books', *books)

print(r.lrange('books', 0, -1))  # ['水浒传', '西游记', '红楼梦', '三国演义']

  • rpush(name, *values)

    • 在name对应的list中添加元素,每个新的元素都添加到列表的最右边 -> 相当于创建一个列表

    • 参数:
      • name: 缓存名
      • values: 要添加的元素,可以接收多个值

    • 写法一

import redis

pool = redis.ConnectionPool(decode_responses=True)
r = redis.Redis(connection_pool=pool)

r.rpush('books', '三国演义', '红楼梦', '西游记', '水浒传')

print(r.lrange('books', 0, -1))  # ['三国演义', '红楼梦', '西游记', '水浒传']

    • 写法二

import redis

pool = redis.ConnectionPool(decode_responses=True)
r = redis.Redis(connection_pool=pool)

books = ['三国演义', '红楼梦', '西游记', '水浒传']
r.rpush('books', *books)

print(r.lrange('books', 0, -1))  # ['三国演义', '红楼梦', '西游记', '水浒传']

  • lpushx(name, value)

    • 在name对应的list中添加元素,只有当name已经存在时,值才会添加到列表的最左边

    • 参数:
      • name: 缓存名
      • value: 要添加的元素,只能接收一个值

import redis

pool = redis.ConnectionPool(decode_responses=True)
r = redis.Redis(connection_pool=pool)

r.lpushx(name='books', value='三体')

print(r.lrange('books', 0, -1))  # 原本的值: ['三国演义', '红楼梦', '西游记', '水浒传'],添加新元素后的值: ['三体', '三国演义', '红楼梦', '西游记', '水浒传']

  • rpushx(name, value)

    • 在name对应的list中添加元素,只有当name已经存在时,值才会添加到列表的最右边

    • 参数:
      • name: 缓存名
      • value: 要添加的元素,只能接收一个值

import redis

pool = redis.ConnectionPool(decode_responses=True)
r = redis.Redis(connection_pool=pool)

r.rpushx(name='books', value='三体')

print(r.lrange('books', 0, -1))  # 原本的值: ['三国演义', '红楼梦', '西游记', '水浒传'],添加新元素后的值: ['三国演义', '红楼梦', '西游记', '水浒传', '三体']

  • llen(name)

    • 获取name对应的list元素的个数

import redis

pool = redis.ConnectionPool(decode_responses=True)
r = redis.Redis(connection_pool=pool)

books_len = r.llen('books')

print(books_len)  # 值: ['三国演义', '红楼梦', '西游记', '水浒传'],长度: 4

  • linsert(name, where, refvalue, value)

    • 在name对应的列表的某一个值前面或后面插入一个新值

    • 如果要在某个值前后插入一个新值,且这某个值有重复,那么只会获取第一个,作为标杆值

    • 参数:
      • name: 缓存名
      • where: BEFORE(之前)/ AFTER(之后)
      • refvalue: 标杆值(即:列表中的值,在它前后插入数据),如果有相同的标杆值,那么只会获取第一个
      • value: 需要插入的数据

import redis

pool = redis.ConnectionPool(decode_responses=True)
r = redis.Redis(connection_pool=pool)

r.linsert(name='books', where='BEFORE', refvalue='红楼梦', value='三体')

print(r.lrange('books', 0, -1))  # 原本的值: ['三国演义', '红楼梦', '红楼梦', '西游记', '水浒传'],添加新元素后的值: ['三国演义', '三体', '红楼梦', '红楼梦', '西游记', '水浒传']

  • lset(name, index, value)

    • 在name对应的list中的指定索引位置重新赋值

    • 参数:
      • name: 缓存名
      • index: 索引
      • value: 需要重新赋值的值

import redis

pool = redis.ConnectionPool(decode_responses=True)
r = redis.Redis(connection_pool=pool)

r.lset(name='books', index=1, value='三体')

print(r.lrange('books', 0, -1))  # 原本的值: ['三国演义', '红楼梦', '西游记', '水浒传'],添加新元素后的值: ['三国演义', '三体', '西游记', '水浒传']

  • lrem(name, count, value)

    • 在name对应的list中删除指定的值

    • 参数:
      • name: 缓存名
      • value: 要删除的值
      • count: 要删除的数量
        • count > 0: 从表头开始向表尾搜索,移除 count 个与value值相等的元素
        • count < 0: 从表尾开始向表头搜索,移除 count的绝对值 个与value值相等的元素
        • count = 0: 移除表中所有与 value 相等的值

    • count > 0: 从表头开始向表尾搜索,移除 count 个与value值相等的元素

import redis

pool = redis.ConnectionPool(decode_responses=True)
r = redis.Redis(connection_pool=pool)

r.lrem(name='books', count=2, value='三国演义')  # count > 0,从表头开始向表尾搜索,移除 2 个与 '三国演义' 相等的值

print(r.lrange('books', 0, -1))  # 原本的值: ['三国演义', '红楼梦', '西游记', '三国演义', '水浒传', '三国演义'],移除相关元素后的值: ['红楼梦', '西游记', '水浒传', '三国演义']

    • count < 0: 从表尾开始向表头搜索,移除 count的绝对值 个与value值相等的元素

import redis

pool = redis.ConnectionPool(decode_responses=True)
r = redis.Redis(connection_pool=pool)

r.lrem(name='books', count=-2, value='三国演义')  # count < 0,从表尾开始向表头搜索,移除 2 个与 三国演义 相等的值

print(r.lrange('books', 0, -1))  # 原本的值: ['三国演义', '红楼梦', '西游记', '三国演义', '水浒传', '三国演义'],移除相关元素后的值: ['三国演义', '红楼梦', '西游记', '水浒传']

    • count = 0: 移除表中所有与 value 相等的值

import redis

pool = redis.ConnectionPool(decode_responses=True)
r = redis.Redis(connection_pool=pool)

r.lrem(name='books', count=0, value='三国演义')  # count = 0,移除表中所有与 三国演义 相等的值

print(r.lrange('books', 0, -1))  # 原本的值: ['三国演义', '红楼梦', '西游记', '三国演义', '水浒传', '三国演义'],移除相关元素后的值: ['红楼梦', '西游记', '水浒传']

  • lpop(name)

    • 删除指定列表的左边第一个元素(即: 列表的一个元素),返回值: 被删除的元素

import redis

pool = redis.ConnectionPool(decode_responses=True)
r = redis.Redis(connection_pool=pool)

del_book = r.lpop('books')

print(r.lrange('books', 0, -1))  # 原本的值: ['三国演义', '红楼梦', '西游记', '水浒传'],移除相关元素后的值: ['红楼梦', '西游记', '水浒传']
print(del_book # 三国演义

  • rpop(name)

    • 删除指定列表的右边第一个元素(即: 列表的最后一个元素),返回值: 被删除的元素

import redis

pool = redis.ConnectionPool(decode_responses=True)
r = redis.Redis(connection_pool=pool)

del_book = r.rpop('books')

print(r.lrange('books', 0, -1))  # 原本的值: ['三国演义', '红楼梦', '西游记', '水浒传'],移除相关元素后的值: ['三国演义', '红楼梦', '西游记']
print(del_book)  # 水浒传

  • lindex(name, index)

    • 在name对应的列表中根据索引获取列表中的元素

    • decode_responses 参数的问题和 get(name) 方法一样(这里就不做演示了)

    • 参数:
      • name: 缓存名
      • index: 索引

import redis

pool = redis.ConnectionPool(decode_responses=True)
r = redis.Redis(connection_pool=pool)

book = r.lindex(name='books', index=2)

print(book)  # 西游记

  • lrange(name, start, end)

    • 切片

    • 只有通过切片才能获取到缓存列表中的所有数据

    • decode_responses 参数的问题和 get(name) 方法一样(这里就不做演示了)

    • 参数:
      • name: 缓存名
      • start: 索引的起始位置
      • end: 索引的结束位置

    • 获取所有数据

import redis

pool = redis.ConnectionPool(decode_responses=True)
r = redis.Redis(connection_pool=pool)

all_data = r.lrange(name='books', start=0, end=-1)

print(all_data)  # ['三国演义', '红楼梦', '西游记', '水浒传']

    • 获取指定区域的数据

import redis

pool = redis.ConnectionPool(decode_responses=True)
r = redis.Redis(connection_pool=pool)

all_data = r.lrange(name='books', start=1, end=2)

print(all_data)  # 所有的数据: ['三国演义', '红楼梦', '西游记', '水浒传'],切片后获取到的数据: ['红楼梦', '西游记']

  • ltrim(name, start, end)

    • 移除name对应列表不在 start-end 范围内的值

    • 和lrange的区别: lrange不修改原列表直接返回切片的结果,ltrim 直接修改原列表

    • 参数:
      • name: 缓存名
      • start: 索引的起始位置
      • end: 索引的结束位置

import redis

pool = redis.ConnectionPool(decode_responses=True)
r = redis.Redis(connection_pool=pool)

all_data = r.ltrim(name='books', start=1, end=2)

print(all_data)  # True
print(r.lrange('books', 0, -1))  # 所有的数据: ['三国演义', '红楼梦', '西游记', '水浒传'],移除后的数据: ['红楼梦', '西游记']

  • rpoplpush(src, dst)

    • 从一个列表取出最右边的元素,同时将其添加至另一个列表的最左边

    • 参数:
      • src: 要取数据的列表的name
      • dst: 要添加数据的列表的name

import redis

pool = redis.ConnectionPool(decode_responses=True)
r = redis.Redis(connection_pool=pool)

r.rpoplpush(src='library1', dst='library2')

print(r.lrange('library1', 0, -1))  # 原本数据: ['book1_1', 'book1_2', 'book1_3'],执行 rpoplpush 后的数据: ['book1_1', 'book1_2']
print(r.lrange('library2', 0, -1))  # 原本数据: ['book2_1', 'book2_2', 'book2_3'],执行 rpoplpush 后的数据: ['book1_3', 'book2_1', 'book2_2', 'book2_3']

  • blpop(keys, timeout)

    • 移出并获取列表的第一个元素,如果列表没有元素就会进入阻塞直到等待超时或发现元素位置(如果没有设置 timeout 或者 timeout=0,那么当列表为空的时候就会阻塞着,直到列表有值)

    • 返回值: 如果列表为空,返回 None,否则,返回一个列表,第一个元素: 本删除元素所属的name,第二元素: 被删除的值

    • decode_responses 参数的问题和 get(name) 方法一样(这里就不做演示了)

    • 参数:
      • keys: 缓存名的集合
      • timeout: 超时时间,当元素所有列表的元素获取完之后,阻塞等待列表内有数据的时间(秒), 0 表示永远阻塞

import redis

pool = redis.ConnectionPool(decode_responses=True)
r = redis.Redis(connection_pool=pool)

r.rpush('list1', '一', '二', '三')
r.rpush('list2', '一', '二', '三')

print(r.blpop(keys=['list1', 'list2', 'list3'], timeout=2))  # ('list1', '一')
print(r.blpop(keys=['list1', 'list2', 'list3'], timeout=2))  # ('list1', '二')
print(r.blpop(keys=['list1', 'list2', 'list3'], timeout=2))  # ('list1', '三')
print(r.blpop(keys=['list1', 'list2', 'list3'], timeout=2))  # ('list2', '一')
print(r.blpop(keys=['list1', 'list2', 'list3'], timeout=2))  # ('list2', '二')
print(r.blpop(keys=['list1', 'list2', 'list3'], timeout=2))  # ('list2', '三')
print(r.blpop(keys=['list1', 'list2', 'list3'], timeout=2))  # None -> 因为 list3 为空

print(r.lrange('list1', 0, -1))  # []
print(r.lrange('list2', 0, -1))  # []

  • brpoplpush(src, dst, timeout=0)

    • 从一个列表的右侧移除一个元素并将其添加到另一个列表的左侧,如果src的列表没有元素就会进入阻塞直到等待超时或发现元素位置(如果没有设置 timeout 或者 timeout=0,那么当列表为空的时候就会阻塞着,直到列表有值)

    • 返回值: src 列表为空,返回None,否者,返回 src 列表被移除的最后一个元素

    • decode_responses 参数的问题和 get(name) 方法一样(这里就不做演示了)

    • 参数:
      • src: 要取数据的列表的name
      • dst: 要添加数据的列表的name
      • 当src对应的列表中没有数据时,阻塞等待其有数据的超时时间(秒),0 表示永远阻塞

import redis

pool = redis.ConnectionPool(decode_responses=True)
r = redis.Redis(connection_pool=pool)

r.rpush('library1', 'book1_1', 'book1_2', 'book1_3')
r.rpush('library2', 'book2_1', 'book2_2', 'book2_3')

print(r.brpoplpush(src='library1', dst='library2', timeout=2))  # book1_3
print(r.brpoplpush(src='library1', dst='library2', timeout=2))  # book1_2
print(r.brpoplpush(src='library1', dst='library2', timeout=2))  # book1_1
print(r.brpoplpush(src='library1', dst='library2', timeout=2))  # None

print(r.lrange('library1', 0, -1))  # []
print(r.lrange('library2', 0, -1))  # ['book1_1', 'book1_2', 'book1_3', 'book2_1', 'book2_2', 'book2_3']

  • 自定义增量迭代

    • 由于redis类库中没有提供对列表元素的增量迭代,如果想要循环name对应的列表的所有元素,那么就需要:
      • 获取name对应的所有列表
      • 循环列表
    • 但是,如果列表非常大,那么就有可能在第一步时就将程序的内容撑爆,所有有必要自定义一个增量迭代的功能:

def list_iter(name):
"""
    自定义redis列表增量迭代
    :param name: redis中的name,即:迭代name对应的列表
    :return: yield 返回 列表元素
    """
    list_count = r.llen(name)
    for index in range(list_count):
        yield r.lindex(name, index)


# 使用
for item in list_iter('pp'):
    print(item)

3.Hash(字典)类型的操作


  • hset(name, key, value)

    • 在name对应的hash中设置一个键值对(不存在,则创建;否则,修改)

    • 参数:
      • name: 缓存名
      • key: name对应的hash中的key
      • value: name对应的hash中的value

import redis

pool = redis.ConnectionPool(decode_responses=True)
r = redis.Redis(connection_pool=pool)

r.hset(name='info', key='username', value='Kevin')

print(r.hgetall('info'))  # {'username': 'Kevin'}

  • hsetnx(name, key, value)

    • 当name对应的hash中不存在当前key时则创建(相当于只做添加)

    • 参数:
      • name: 缓存名
      • key: name对应的hash中的key
      • value: name对应的hash中的value

import redis

pool = redis.ConnectionPool(decode_responses=True)
r = redis.Redis(connection_pool=pool)

r.hsetnx(name='info', key='age', value='18')

print(r.hgetall('info'))  # {'username': 'Kevin', 'age': '18'}

  • hmset(name, mapping)

    • 在name对应的hash中批量设置键值对

    • 参数:
      • name: 缓存名
      • mapping: 字典,如:{'k1':'v1', 'k2': 'v2'}

import redis

pool = redis.ConnectionPool(decode_responses=True)
r = redis.Redis(connection_pool=pool)

r.hmset(name='info', mapping={'username': 'Kevin', 'age': '18'})

print(r.hgetall('info'))  # {'age': '18', 'username': 'Kevin'}

  • 添加嵌套 hash 的方法

    • 方法一:

      • 使用 json.dumps 序列化字典

import redis
import json

pool = redis.ConnectionPool(decode_responses=True)
r = redis.Redis(connection_pool=pool)

r.hmset(name='info', mapping={
    'username': 'Kevin',
    'age': 18,
    'address': json.dumps({
        'province': '广东省',
        'city': '东莞市',
        'town': '南城'
    })
})

print(r.hgetall('info'))  # {'username': 'Kevin', 'address': '{"province": "\\u5e7f\\u4e1c\\u7701", "town": "\\u5357\\u57ce", "city": "\\u4e1c\\u839e\\u5e02"}', 'age': '18'}

json_address = r.hget('info', 'address')
address = json.loads(json_address)

print(address)  # {'province': '广东省', 'city': '东莞市', 'town': '南城'}

    • 方法二:

      • 使用: r.set + json.dumps

import redis
import json

pool = redis.ConnectionPool(decode_responses=True)
r = redis.Redis(connection_pool=pool)

info_dic = {
    'username': 'Kevin',
    'age': 18,
    'address': {
        'province': '广东省',
        'city': '东莞市',
        'town': '南城'
    }
}

r.set(name='info', value=json.dumps(info_dic))

print(r.get('info'))  # {"username": "Kevin", "age": 18, "address": {"town": "\u5357\u57ce", "city": "\u4e1c\u839e\u5e02", "province": "\u5e7f\u4e1c\u7701"'+'}'+'}'}}

json_info = r.get('info')
info = json.loads(json_info)
address = info['address']
print(address)  # {'province': '广东省', 'city': '东莞市', 'town': '南城'}

    • 错误示范

      • 不要直接编写嵌套 hash,因为不是json结构,无法通过 json.loads 解析出来

import redis

pool = redis.ConnectionPool(decode_responses=True)
r = redis.Redis(connection_pool=pool)

r.hmset(name='info', mapping={
    'username': 'Kevin',
    'age': 18,
    'address': {  # 必须是序列化后的字符串
        'province': '广东省',
        'city': '东莞市',
        'town': '南城'
    }
})

  • hget(name, key)

    • 在name对应的hash中根据key获取value

    • decode_responses 参数的问题和 get(name) 方法一样(这里就不做演示了)

    • 参数:
      • name: 缓存名
      • key: name对应的hash中的key

import redis

pool = redis.ConnectionPool(decode_responses=True)
r = redis.Redis(connection_pool=pool)

username = r.hget(name='info', key='username')

print(username)  # Kevin

  • hmget(name, keys, *args)

    • 在name对应的hash中获取多个key所对应的value值(即: 批量获取key的value值)

    • decode_responses 参数的问题和 get(name) 方法一样(这里就不做演示了)

    • 参数:
      • name: 缓存名
      • keys: key的集合,如: ['k1', 'k2', 'k3']
      • *args: keys 打散后的结果,如: k1, k2, k3

    • 写法一

import redis

pool = redis.ConnectionPool(decode_responses=True)
r = redis.Redis(connection_pool=pool)

info_values = r.hmget(name='info', keys=['username', 'age'])

print(info_values)  # ['Kevin', '18']

    • 写法二

import redis

pool = redis.ConnectionPool(decode_responses=True)
r = redis.Redis(connection_pool=pool)

info_values = r.hmget('info', 'username', 'age')

print(info_values)  # ['Kevin', '18']

  • hgetall(name)

    • 获取name对应hash的所有键值对

    • decode_responses 参数的问题和 get(name) 方法一样(这里就不做演示了)

    • 参数:
      • name: 缓存名

import redis

pool = redis.ConnectionPool(decode_responses=True)
r = redis.Redis(connection_pool=pool)

info = r.hgetall('info')

print(info)  # {'username': 'Kevin', 'age': '18'}

  • hlen(name)

    • 获取name对应的hash中键值对的个数

    • 参数:
      • name: 缓存名

import redis

pool = redis.ConnectionPool(decode_responses=True)
r = redis.Redis(connection_pool=pool)

info_len = r.hlen('info')

print(info_len)  # 值: {'username': 'Kevin', 'age': '18'},长度: 2

  • hkeys(name)

    • 获取name对应的hash中所有的key的值

    • decode_responses 参数的问题和 get(name) 方法一样(这里就不做演示了)

    • 参数:
      • name: 缓存名

import redis

pool = redis.ConnectionPool(decode_responses=True)
r = redis.Redis(connection_pool=pool)

info_keys = r.hkeys('info')

print(info_keys)  # ['age', 'username']

  • hvals(name)

    • 获取name对应的hash中所有的value的值

    • decode_responses 参数的问题和 get(name) 方法一样(这里就不做演示了)

    • 参数:
      • name: 缓存名

import redis

pool = redis.ConnectionPool(decode_responses=True)
r = redis.Redis(connection_pool=pool)

info_values = r.hvals('info')

print(info_values)  # ['18', 'Kevin']

  • hexists(name, key)

    • 检查name对应的hash是否存在当前传入的key

    • 参数:
      • name: 缓存名
      • key: 需要检测的 key 名字

    • 返回值: True/False

import redis

pool = redis.ConnectionPool(decode_responses=True)
r = redis.Redis(connection_pool=pool)

has_key = r.hexists(name='info', key='address')
print(has_key)  # 值: {'age': '18', 'username': 'Kevin'},检测结果: False

has_key = r.hexists(name='info', key='username')
print(has_key)  # 值: {'age': '18', 'username': 'Kevin'},检测结果: True

  • hdel(name, *keys)

    • 将name对应的hash中指定key的键值对删除(即: 删除指定的键值对)

      • 写法一

import redis

pool = redis.ConnectionPool(decode_responses=True)
r = redis.Redis(connection_pool=pool)

r.hdel('info', 'username', 'age')

print(r.hgetall('info'))  # 原本的值: {'username': 'Kevin', 'age': '18', 'address': '广东'},删除后的值: {'address': '广东'}

      • 写法二

import redis

pool = redis.ConnectionPool(decode_responses=True)
r = redis.Redis(connection_pool=pool)

del_keys = ['username', 'age']

r.hdel('info', *del_keys)

print(r.hgetall('info'))  # 原本的值: {'username': 'Kevin', 'age': '18', 'address': '广东'},删除后的值: {'address': '广东'}

    • 将name对应的hash中的键值对清空

import redis

pool = redis.ConnectionPool(decode_responses=True)
r = redis.Redis(connection_pool=pool)

info_keys = r.hkeys('info')  # 获取 info 的所有 key 值

r.hdel('info', *info_keys)

print(r.hgetall('info'))  # 原本的值: {'username': 'Kevin', 'age': '18', 'address': '广东'},删除后的值: {}

  • hincrby(name, key, amount)

    • 整数自增name对应的hash中的指定key的值,当key不存在时,则创建key=amount,否则,进行整数自增

    • 需要自增的value必须是整数

    • 参数: 
      • name: 缓存名
      • key: name对应的hash中的key
      • amount: 每次自增的数量(即: 每次添加的数量),必须是整数

import redis

pool = redis.ConnectionPool(decode_responses=True)
r = redis.Redis(connection_pool=pool)

r.hincrby(name='info', key='age', amount=2)

print(r.hgetall('info'))  # 原本的值: {'username': 'Kevin', 'age': '18'},自增后的值: {'username': 'Kevin', 'age': '20'}

  • hincrbyfloat(name, key, amount)

    • 浮点数自增name对应的hash中的指定key的值,当key不存在时,则创建key=amount,否则,进行浮点数自增

    • 需要自增的value可以是整数或浮点数

    • 参数: 
      • name: 缓存名
      • key: name对应的hash中的key
      • amount: 每次自增的数量(即: 每次添加的数量),可以是整数或浮点数

import redis

pool = redis.ConnectionPool(decode_responses=True)
r = redis.Redis(connection_pool=pool)

r.hincrbyfloat(name='info', key='age', amount=2.5)

print(r.hgetall('info'))  # 原本的值: {'username': 'Kevin', 'age': '20'},自增后的值: {'username': 'Kevin', 'age': '22.5'}

  • hscan(name, cursor, match, count)

    • 增量式迭代获取,对于数据大的数据非常有用,hscan可以实现分片的获取数据,并非一次性将数据全部获取完,从而防止内存被撑爆

    • 当 hash 中的键值对数量过少的时候,hscan 是无效的

    • decode_responses 参数的问题和 get(name) 方法一样(这里就不做演示了)

    • 参数:
      • name: 缓存名
      • cursor: 游标(基于游标分批取获取数据)
      • match: 匹配指定key,默认None 表示所有的key
      • count: 每次分片最少获取个数,默认None表示采用redis的默认分片个数

    • 返回值:
      • 返回值有两个
      • 第一个: 游标 -> 当游标为0的时候表示数据以及获取完
      • 第二个: 获取到的值

    • 说明 hscan 的用法的写法

import redis

pool = redis.ConnectionPool(decode_responses=True)
r = redis.Redis(connection_pool=pool)

# 写入 1024 条数据
# for i in range(1024):
#     r.hmset('info', {
#         'username%s' % i: 'Kevin', 'age%s' % i: '18',
#     })

cursor1, data1 = r.hscan('info', cursor=0, match=None, count=None)
print(cursor1, data1)  # 1408 {'age873': '18', 'age834': '18', 'username817': 'Kevin', 'age370': '18', 'age49': '18', 'age349': '18', 'age420': '18', 'username647': 'Kevin', 'username309': 'Kevin', 'age25': '18', 'username261': 'Kevin'}
cursor2, data2 = r.hscan('info', cursor=cursor1, match=None, count=None)
print(cursor2, data2)  # 1344 {'age880': '18', 'username439': 'Kevin', 'username964': 'Kevin', 'age640': '18', 'age769': '18', 'username807': 'Kevin', 'age478': '18', 'age605': '18', 'username629': 'Kevin', 'age990': '18', 'username457': 'Kevin'}
cursor1, data1 = r.hscan('info', cursor=cursor2, match=None, count=None)
print(cursor1, data1)  # 1472 {'username1011': 'Kevin', 'username494': 'Kevin', 'age329': '18', 'username987': 'Kevin', 'age426': '18', 'username927': 'Kevin', 'age993': '18', 'username884': 'Kevin', 'username786': 'Kevin', 'username624': 'Kevin'}

    • 实际应用写法

import redis

pool = redis.ConnectionPool(decode_responses=True)
r = redis.Redis(connection_pool=pool)

# 写入 1024 条数据
# for i in range(1024):
#     r.hmset('info', {
#         'username%s' % i: 'Kevin', 'age%s' % i: '18',
#     })

cursor = 1

while cursor:
    cursor, data = r.hscan('info', cursor=cursor, match=None, count=None)
    print(cursor, data)

  • hscan_iter(name, match, count)

    • hscan_iter利用yield封装hscan创建的生成器,实现分批去redis中获取数据

    • decode_responses 参数的问题和 get(name) 方法一样(这里就不做演示了)

    • 参数:
      • name: 缓存名
      • match: 匹配指定key,默认None 表示所有的key
      • count: 每次分片最少获取个数,默认None表示采用redis的默认分片个数

import redis

pool = redis.ConnectionPool(decode_responses=True)
r = redis.Redis(connection_pool=pool)

# 写入 1024 条数据
# for i in range(1024):
#     r.hmset('info', {
#         'username%s' % i: 'Kevin', 'age%s' % i: '18',
#     })

for i in r.hscan_iter('info'):
    print(i)

4. Set(集合)类型的操作,不允许有重复数据的列表


  • sadd(name, values)

    • 在 name 对应的集合中添加元素

    • 参数:
      • name: 缓存名
      • values: 要添加的元素,可以接收多个值

    • 写法一

import redis

pool = redis.ConnectionPool(decode_responses=True)
r = redis.Redis(connection_pool=pool)

r.sadd('books', '三国演义', '红楼梦', '西游记', '水浒传')

print(r.smembers('books'))  # {'红楼梦', '三国演义', '西游记', '水浒传'}

    • 写法二

import redis

pool = redis.ConnectionPool(decode_responses=True)
r = redis.Redis(connection_pool=pool)

books = ['三国演义', '红楼梦', '西游记', '水浒传']

r.sadd('books', *books)

print(r.smembers('books'))  # {'红楼梦', '三国演义', '西游记', '水浒传'}

  • scard(name)

    • 获取name对应的集合中元素个数

import redis

pool = redis.ConnectionPool(decode_responses=True)
r = redis.Redis(connection_pool=pool)

books_len = r.scard('books')

print(books_len)  # 值: {'红楼梦', '三国演义', '西游记', '水浒传'},长度: 4

  • sdiff(keys, *args)

    • 返回多个集合之间的差集

    • 参数:
      • keys: 缓存名的集合,如: ['k1', 'k2', 'k3']
      • *args: 缓存名的集合打散后的结果,如: k1, k2, k3

    • decode_responses 参数的问题和 get(name) 方法一样(这里就不做演示了)

    • 写法一

import redis

pool = redis.ConnectionPool(decode_responses=True)
r = redis.Redis(connection_pool=pool)

r.sadd('library1', '三国演义', '红楼梦', '匆匆那年', '水浒传')
r.sadd('library2', '三国演义', '三体', '西游记', '水浒传')

diff = r.sdiff(['library1', 'library2'])

print(diff)  # {'匆匆那年', '红楼梦'}

    • 写法二

import redis

pool = redis.ConnectionPool(decode_responses=True)
r = redis.Redis(connection_pool=pool)

r.sadd('library1', '三国演义', '红楼梦', '匆匆那年', '水浒传')
r.sadd('library2', '三国演义', '三体', '西游记', '水浒传')

diff = r.sdiff('library1', 'library2')

print(diff)  # {'匆匆那年', '红楼梦'}

  • sdiffstore(dest, keys, *args)

    • 将集合之间的差集存储在指定的集合中,如果指定的集合已存在,则会将其覆盖

    • 参数:
      • dest: 存储差集的集合名称
      • keys:缓存名的集合,如: ['k1', 'k2', 'k3']
      • *args: 缓存名的集合打散后的结果,如: k1, k2, k3

    • 写法一

import redis

pool = redis.ConnectionPool(decode_responses=True)
r = redis.Redis(connection_pool=pool)

r.sadd('library1', '三国演义', '红楼梦', '匆匆那年', '水浒传')
r.sadd('library2', '三国演义', '三体', '西游记', '水浒传')

r.sadd('save_diff', 'testdata')
r.sdiffstore(dest='save_diff', keys=['library1', 'library2'])

print(r.smembers('save_diff'))  # {'匆匆那年', '红楼梦'}

    • 写法二

import redis

pool = redis.ConnectionPool(decode_responses=True)
r = redis.Redis(connection_pool=pool)

r.sadd('library1', '三国演义', '红楼梦', '匆匆那年', '水浒传')
r.sadd('library2', '三国演义', '三体', '西游记', '水浒传')

r.sadd('save_diff', 'testdata')
r.sdiffstore('save_diff', 'library1', 'library2')

print(r.smembers('save_diff'))  # {'匆匆那年', '红楼梦'}

  • sinter(keys, *args)

    • 返回多个集合之间的交集,不存在的集合 key 被视为空集,当给定集合当中有一个空集时,结果也为空集

    • 参数:
      • keys: 缓存名的集合,如: ['k1', 'k2', 'k3']
      • *args: 缓存名的集合打散后的结果,如: k1, k2, k3

    • decode_responses 参数的问题和 get(name) 方法一样(这里就不做演示了)

    • 写法一

import redis

pool = redis.ConnectionPool(decode_responses=True)
r = redis.Redis(connection_pool=pool)

r.sadd('library1', '三国演义', '红楼梦', '匆匆那年', '水浒传')
r.sadd('library2', '三国演义', '三体', '西游记', '水浒传')

inter = r.sinter(['library1', 'library2'])

print(inter)  # {'三国演义', '水浒传'}

    • 写法二

import redis

pool = redis.ConnectionPool(decode_responses=True)
r = redis.Redis(connection_pool=pool)

r.sadd('library1', '三国演义', '红楼梦', '匆匆那年', '水浒传')
r.sadd('library2', '三国演义', '三体', '西游记', '水浒传')

inter = r.sinter('library1', 'library2')

print(inter)  # {'三国演义', '水浒传'}

  • sinterstore(dest, keys, *args)

    • 将集合之间的交集存储在指定的集合中,如果指定的集合已存在,则会将其覆盖

    • 参数:
      • dest: 存储交集的集合名称
      • keys:缓存名的集合,如: ['k1', 'k2', 'k3']
      • *args: 缓存名的集合打散后的结果,如: k1, k2, k3

    • 写法一

import redis

pool = redis.ConnectionPool(decode_responses=True)
r = redis.Redis(connection_pool=pool)

r.sadd('library1', '三国演义', '红楼梦', '匆匆那年', '水浒传')
r.sadd('library2', '三国演义', '三体', '西游记', '水浒传')

r.sadd('save_inter', 'testdata')
r.sinterstore(dest='save_inter', keys=['library1', 'library2'])

print(r.smembers('save_inter'))  # {'水浒传', '三国演义'}

    • 写法二

import redis

pool = redis.ConnectionPool(decode_responses=True)
r = redis.Redis(connection_pool=pool)

r.sadd('library1', '三国演义', '红楼梦', '匆匆那年', '水浒传')
r.sadd('library2', '三国演义', '三体', '西游记', '水浒传')

r.sadd('save_inter', 'testdata')
r.sinterstore('save_inter', 'library1', 'library2')

print(r.smembers('save_inter'))  # {'水浒传', '三国演义'}

  • sunion(keys, *args)

    • 返回多个集合之间的并集,不存在的集合 key 被视为空集,当给定集合当中有一个空集时,结果也为空集

    • 参数:
      • keys: 缓存名的集合,如: ['k1', 'k2', 'k3']
      • *args: 缓存名的集合打散后的结果,如: k1, k2, k3

    • decode_responses 参数的问题和 get(name) 方法一样(这里就不做演示了)

    • 写法一

import redis

pool = redis.ConnectionPool(decode_responses=True)
r = redis.Redis(connection_pool=pool)

r.sadd('library1', '三国演义', '红楼梦', '匆匆那年', '水浒传')
r.sadd('library2', '三国演义', '三体', '西游记', '水浒传')

union = r.sunion(['library1', 'library2'])

print(union)  # {'三国演义', '水浒传', '匆匆那年', '三体', '红楼梦', '西游记'}

    • 写法二

import redis

pool = redis.ConnectionPool(decode_responses=True)
r = redis.Redis(connection_pool=pool)

r.sadd('library1', '三国演义', '红楼梦', '匆匆那年', '水浒传')
r.sadd('library2', '三国演义', '三体', '西游记', '水浒传')

union = r.sunion('library1', 'library2')

print(union)  # {'三国演义', '水浒传', '匆匆那年', '三体', '红楼梦', '西游记'}

  • sunionstore(dest, keys, *args)

    • 将集合之间的并集存储在指定的集合中,如果指定的集合已存在,则会将其覆盖

    • 参数:
      • dest: 存储并集的集合名称
      • keys:缓存名的集合,如: ['k1', 'k2', 'k3']
      • *args: 缓存名的集合打散后的结果,如: k1, k2, k3

    • 写法一

import redis

pool = redis.ConnectionPool(decode_responses=True)
r = redis.Redis(connection_pool=pool)

r.sadd('library1', '三国演义', '红楼梦', '匆匆那年', '水浒传')
r.sadd('library2', '三国演义', '三体', '西游记', '水浒传')

r.sadd('save_union', 'testdata')
r.sunionstore(dest='save_union', keys=['library1', 'library2'])

print(r.smembers('save_union'))  # {'匆匆那年', '水浒传', '三国演义', '三体', '西游记', '红楼梦'}

    • 写法二

import redis

pool = redis.ConnectionPool(decode_responses=True)
r = redis.Redis(connection_pool=pool)

r.sadd('library1', '三国演义', '红楼梦', '匆匆那年', '水浒传')
r.sadd('library2', '三国演义', '三体', '西游记', '水浒传')

r.sadd('save_union', 'testdata')
r.sunionstore('save_union', 'library1', 'library2')

print(r.smembers('save_union'))  # {'匆匆那年', '水浒传', '三国演义', '三体', '西游记', '红楼梦'}

  • sismember(name, value)

    • 检查value是否是name对应的集合的成员

    • 参数:
      • name: 缓存名
      • value: 需要检测的值

import redis

pool = redis.ConnectionPool(decode_responses=True)
r = redis.Redis(connection_pool=pool)

is_has = r.sismember(name='info', value='三国演义')

print(is_has)  # 值: {'三国演义', '红楼梦', '水浒传', '西游记'},检测后的结果: True

  • smove(src, dst, value)

    • 将某个成员从一个集合中移动到另外一个集合

    • 参数:
      • src: 要取数据的集合的name
      • dst: 要添加数据的集合的name
      • value: 要取的数据

import redis

pool = redis.ConnectionPool(decode_responses=True)
r = redis.Redis(connection_pool=pool)

r.sadd('library1', '三国演义', '红楼梦', '匆匆那年', '水浒传')
r.sadd('library2', '三国演义', '三体', '西游记', '水浒传')

r.smove(src='library1', dst='library2', value='匆匆那年')

print(r.smembers('library1'))  # {'三国演义', '红楼梦', '水浒传'}
print(r.smembers('library2'))  # {'三国演义', '匆匆那年', '三体', '西游记', '水浒传'}

  • spop(name)

    • 删除集合中的最后一个成员,并将其返回

import redis

pool = redis.ConnectionPool(decode_responses=True)
r = redis.Redis(connection_pool=pool)

del_data = r.spop('books')

print(del_data)  # 西游记

  • srandmember(name, numbers)

    • 从 name 对应的集合中随机获取 numbers 个元素

    • decode_responses 参数的问题和 get(name) 方法一样(这里就不做演示了)

    • 参数:
      • name: 缓存名
      • numbers: 获取集合的成员个数

import redis

pool = redis.ConnectionPool(decode_responses=True)
r = redis.Redis(connection_pool=pool)

r.sadd('books', '三国演义', '红楼梦', '水浒传', '西游记')

random_book = r.srandmember(name='books', number=3)

print(random_book)  # ['红楼梦', '水浒传', '三国演义']

  • srem(name, values)

    • 移除集合中的一个或多个成员元素,不存在的成员元素会被忽略

    • 参数:
      • name: 缓存名
      • values: 要移除的元素,可以接收多个值

    • 写法一

import redis

pool = redis.ConnectionPool(decode_responses=True)
r = redis.Redis(connection_pool=pool)

r.srem('books', '红楼梦', '水浒传')

print(r.smembers('books'))  # 原本的值: {'三国演义', '红楼梦', '水浒传', '西游记'},删除后的值: {'三国演义', '西游记'}

    • 写法二

import redis

pool = redis.ConnectionPool(decode_responses=True)
r = redis.Redis(connection_pool=pool)

books = ['红楼梦', '水浒传']
r.srem('books', *books)

print(r.smembers('books'))  # 原本的值: {'三国演义', '红楼梦', '水浒传', '西游记'},删除后的值: {'三国演义', '西游记'}

  • sscan(name, cursor, match, count)

    • 增量式迭代获取,对于数据大的数据非常有用,sscan可以实现分片的获取数据,并非一次性将数据全部获取完,从而防止内存被撑爆

    • 当集合中的成员数量过少的时候,sscan 是无效的

    • decode_responses 参数的问题和 get(name) 方法一样(这里就不做演示了)

    • 参数:
      • name: 缓存名
      • cursor: 游标(基于游标分批取获取数据)
      • match: 匹配指定key,默认None 表示所有的key
      • count: 每次分片最少获取个数,默认None表示采用redis的默认分片个数

    • 返回值:
      • 返回值有两个
      • 第一个: 游标 -> 当游标为0的时候表示数据以及获取完
      • 第二个: 获取到的值

    • 说明 sscan 的用法的写法

import redis

pool = redis.ConnectionPool(decode_responses=True)
r = redis.Redis(connection_pool=pool)

# 写入 1024 条数据
# for i in range(1024):
#     r.sadd('set_list', '数据%s' % i)

cursor1, data1 = r.sscan('set_list', cursor=0, match=None, count=None)
print(cursor1, data1)  # 896 ['数据235', '数据1002', '数据148', '数据719', '数据418', '数据754', '数据385', '数据715', '数据849', '数据1001']
cursor2, data2 = r.sscan('set_list', cursor=cursor1, match=None, count=None)
print(cursor2, data2)  # 928 ['数据161', '数据976', '数据554', '数据126', '数据258', '数据328', '数据112', '数据707', '数据533', '数据115']
cursor1, data1 = r.sscan('set_list', cursor=cursor2, match=None, count=None)
print(cursor1, data1)  # 272 ['数据947', '数据721', '数据335', '数据127', '数据965', '数据79', '数据870', '数据455', '数据681', '数据307', '数据933']

    • 实际应用写法

import redis

pool = redis.ConnectionPool(decode_responses=True)
r = redis.Redis(connection_pool=pool)

# 写入 1024 条数据
# for i in range(1024):
#     r.sadd('set_list', '数据%s' % i)

cursor = 1

while cursor:
    cursor, data = r.sscan('set_list', cursor=cursor, match=None, count=None)
    print(cursor, data)

  • sscan_iter(name, match, count)

    • sscan_iter利用yield封装sscan创建的生成器,实现分批去redis中获取数据

    • decode_responses 参数的问题和 get(name) 方法一样(这里就不做演示了)

    • 参数:
      • name: 缓存名
      • match: 匹配指定key,默认None 表示所有的key
      • count: 每次分片最少获取个数,默认None表示采用redis的默认分片个数

import redis

pool = redis.ConnectionPool(decode_responses=True)
r = redis.Redis(connection_pool=pool)

# 写入 1024 条数据
# for i in range(1024):
#     r.sadd('set_list', '数据%s' % i)

for i in r.sscan_iter('set_list'):
    print(i)

5. Sorted Set(有序集合)类型的操作


  • 有序集合: 
    • 在集合的基础上,为每元素排序;
    • 元素的排序需要根据另外一个值来进行比较,所以,对于有序集合,每一个元素有两个值,即:值和分数,分数专门用来做排序

  • zadd(name, mapping, nx, xx, ch, incr)

    • 在name对应的有序集合中添加元素

    • 参数:
      • name: 缓存名
      • mapping: 字典,如 {'值': 分数} -> {'value': 1}
      • nx: 如果值为 True,当 name 不存在的时候,当前set操作才会执行
      • xx: 如果值为 True,当 name 存在的时候,当前set操作才会执行
      • ch: 如果值为 True,那么返回值就是添加或修改了多少个元素的个数
      • incr: 自增(+1),如果值为True,那么就会对某一个元素的分数自加1,且返回值是该元素的分数自加1的结果,并且 mapping 参数只能有一个键值对

    • 一般的使用

import redis

pool = redis.ConnectionPool(decode_responses=True)
r = redis.Redis(connection_pool=pool)

r.zadd(name='s_set', mapping={'n1': 1, 'n2': 2, 'n3': 3})  # 根据分数进行排序,且 value 就是分数,key就是有序集合的值

print(r.zrange('s_set', 0, -1, withscores=True))  # [('n1', 1.0), ('n2', 2.0), ('n3', 3.0)]

    • ch=True

import redis

pool = redis.ConnectionPool(decode_responses=True)
r = redis.Redis(connection_pool=pool)

add_num = r.zadd(name='s_set', mapping={'n1': 1, 'n2': 2, 'n3': 3, 'n4': 4, 'n5': 5}, ch=True)

print(add_num)  # 2

    • incr=True

import redis

pool = redis.ConnectionPool(decode_responses=True)
r = redis.Redis(connection_pool=pool)

add_num = r.zadd(name='s_set', mapping={'n1': 1}, incr=True)

print(r.zrange('s_set', 0, -1, withscores=True))  # 原本的值: [('n1', 1.0), ('n2', 2.0), ('n3', 3.0)],当 incr=True 并且执行2次后: [('n2', 2.0), ('n1', 3.0), ('n3', 3.0)]

  • zcard(name)

    • 获取name对应的有序集合元素的数量

import redis

pool = redis.ConnectionPool(decode_responses=True)
r = redis.Redis(connection_pool=pool)

s_set_len = r.zcard('s_set')

print(s_set_len)  # 值: [('n1', 1.0), ('n2', 2.0), ('n3', 3.0)],长度: 3

  • zcount(name, min, max)

    • 获取在 min-max 范围分数的个数

    • 参数:
      • name: 缓存名
      • min: 分数最小值
      • max: 分数最大值

import redis

pool = redis.ConnectionPool(decode_responses=True)
r = redis.Redis(connection_pool=pool)

fraction_len = r.zcount(name='s_set', min=2, max=4)

print(fraction_len)  # 值: [('n1', 1.0), ('n2', 2.0), ('n3', 3.0), ('n4', 4.0), ('n5', 5.0)],长度: 3

  • zincrby(name, value, amount)

    • 自增name对应的有序集合的 value 对应的分数

    • 参数:
      • name: 缓存名
      • value: 需要自增分数的value
      • amount: 每次自增的数量(即: 每次添加的数量),必须是整数

import redis

pool = redis.ConnectionPool(decode_responses=True)
r = redis.Redis(connection_pool=pool)

r.zincrby(name='s_set', value='n1', amount=2)  # 当前 n1 的分数为 1,自增后 n1 的分数为 3

print(r.zrange('s_set', 0, -1, withscores=True))  # 没有自增前的值: [('n1', 1.0), ('n2', 2.0), ('n3', 3.0)],自增后的值: [('n2', 2.0), ('n1', 3.0), ('n3', 3.0)]

  • r.zrange(name, start, end, desc, withscores, score_cast_func)

    • 切片 + 排序 + 分数的显示

    • decode_responses 参数的问题和 get(name) 方法一样(这里就不做演示了)

    • 参数:
      • name: 缓存名
      • start: 有序集合索引起始位置(非分数)
      • end: 有序集合索引结束位置(非分数)
      • desc: 如果值True,那么就按照分数的降序排序,否则按照分数升序排序
      • withscores: 是否获取元素的分数,默认只获取元素的值
      • score_cast_func: 对分数进行数据转换的函数,默认使用的函数是 float,可以修改为 int

    • 基本使用

import redis

pool = redis.ConnectionPool(decode_responses=True)
r = redis.Redis(connection_pool=pool)

r.zadd(name='s_set', mapping={'n1': 1, 'n2': 2, 'n3': 3, 'n4': 4, 'n5': 5})

s_set = r.zrange(name='s_set', start=1, end=3, desc=True, withscores=True, score_cast_func=int)

print(s_set)  # [('n4', 4), ('n3', 3), ('n2', 2)]

    • 获取有序集合的所有数据

import redis

pool = redis.ConnectionPool(decode_responses=True)
r = redis.Redis(connection_pool=pool)

r.zadd(name='s_set', mapping={'n1': 1, 'n2': 2, 'n3': 3, 'n4': 4, 'n5': 5})

s_set = r.zrange(name='s_set', start=0, end=-1, withscores=True, score_cast_func=int)

print(s_set)  # [('n1', 1), ('n2', 2), ('n3', 3), ('n4', 4), ('n5', 5)]

  • zrank(name, value)

    • 获取某个值在name对应的有序集合中的排行(先进行从小到大的排序,然后在进行获取) -> 从 0 开始算起

    • 参数
      • name: 缓存名
      • value: 需要获取排行的值

import redis

pool = redis.ConnectionPool(decode_responses=True)
r = redis.Redis(connection_pool=pool)

rank = r.zrank(name='s_set', value='n2')

print(rank)  # 有序集合的值: [('n1', 1), ('n2', 2), ('n3', 3), ('n4', 4), ('n5', 5)],n2 的排行: 1

  • zrevrank(name, value)

    • 获取某个值在name对应的有序集合中的排行(先进行从大到小的排序,然后在进行获取) -> 从 0 开始算起

    • 参数
      • name: 缓存名
      • value: 需要获取排行的值

import redis

pool = redis.ConnectionPool(decode_responses=True)
r = redis.Redis(connection_pool=pool)

rank = r.zrevrank(name='s_set', value='n2')

print(rank)  # 有序集合的值: [('n1', 1), ('n2', 2), ('n3', 3), ('n4', 4), ('n5', 5)],n2 的排行: 3

  • zrangebylex(name, min, max, start, num)

# 当有序集合的所有成员都具有相同的分值时,有序集合的元素会根据成员的 值 (lexicographical ordering)来进行排序,而这个命令则可以返回给定的有序集合键 key 中, 元素的值介于 min 和 max 之间的成员

# 对集合中的每个成员进行逐个字节的对比(byte-by-byte compare), 并按照从低到高的顺序, 返回排序后的集合成员。 如果两个字符串有一部分内容是相同的话, 那么命令会认为较长的字符串比较短的字符串要大

# 参数:
    # name,redis的name
    # min,左区间(值)。 + 表示正无限; - 表示负无限; ( 表示开区间; [ 则表示闭区间
    # min,右区间(值)
    # start,对结果进行分片处理,索引位置
    # num,对结果进行分片处理,索引后面的num个元素

# 如:
    # ZADD myzset 0 aa 0 ba 0 ca 0 da 0 ea 0 fa 0 ga
    # r.zrangebylex('myzset', "-", "[ca") 结果为:['aa', 'ba', 'ca']

# 更多:
    # 从大到小排序
    # zrevrangebylex(name, max, min, start=None, num=None)

  • zrem(name, values)

    • 移除有序集中的一个或多个成员,不存在的成员将被忽略

    • 参数:
      • name: 缓存名
      • values: 要移除的元素,可以接收多个值

    • 写法一

import redis

pool = redis.ConnectionPool(decode_responses=True)
r = redis.Redis(connection_pool=pool)

r.zrem('s_set', 'n2', 'n3', 'n4')

print(r.zrange('s_set', 0, -1, withscores=True, score_cast_func=int))  # 未移除任何元素前的值: [('n1', 1), ('n2', 2), ('n3', 3), ('n4', 4), ('n5', 5)],移除某些元素后的值: [('n1', 1), ('n5', 5)]

    • 写法二

import redis

pool = redis.ConnectionPool(decode_responses=True)
r = redis.Redis(connection_pool=pool)

r_s_set = ['n2', 'n3', 'n4']
r.zrem('s_set', *r_s_set)

print(r.zrange('s_set', 0, -1, withscores=True, score_cast_func=int))  # 未移除任何元素前的值: [('n1', 1), ('n2', 2), ('n3', 3), ('n4', 4), ('n5', 5)],移除某些元素后的值: [('n1', 1), ('n5', 5)]

  • zremrangebyrank(name, min, max)

    • 删除在 min-max 范围排行内的成员 -> (从大到小的排序,从0开始算起)

    • 参数:
      • name: 缓存名
      • min: 最小排行数
      • max: 最大排行树

import redis

pool = redis.ConnectionPool(decode_responses=True)
r = redis.Redis(connection_pool=pool)

r.zadd(name='s_set', mapping={'n1': 1, 'n2': 2, 'n3': 3, 'n4': 4, 'n5': 5})

r.zremrangebyrank(name='s_set', min=1, max=3)

print(r.zrange('s_set', 0, -1, withscores=True, score_cast_func=int))  # [('n1', 1), ('n5', 5)]

  • zremrangebyscore(name, min, max)

    • 删除在 min-max 范围分数内的成员 -> (从大到小的排序,从1开始算起)

    • 参数:
      • name: 缓存名
      • min: 最小分数
      • max: 最大分树

import redis

pool = redis.ConnectionPool(decode_responses=True)
r = redis.Redis(connection_pool=pool)

r.zadd(name='s_set', mapping={'n1': 1, 'n2': 2, 'n3': 3, 'n4': 4, 'n5': 5})

r.zremrangebyscore(name='s_set', min=1, max=3)

print(r.zrange('s_set', 0, -1, withscores=True, score_cast_func=int))  # [('n4', 4), ('n5', 5)]

  • zremrangebylex(name, min, max)

# 根据值返回删除

  • zscore(name, value)

    • 获取name对应有序集合中 value 对应的分数

    • 参数:
      • name: 缓存名
      • value: 要获取分数的value值

import redis

pool = redis.ConnectionPool(decode_responses=True)
r = redis.Redis(connection_pool=pool)

fraction = r.zscore(name='s_set', value='n3')

print(fraction)  # 3.0

  • zinterstore(dest, keys, aggregate)

    • 将有序集合之间的交集存储在指定的有序集合中,如果指定的有序集合已存在,则会将其覆盖,如果遇到相同值不同分数,则按照aggregate进行操作

    • 参数:
      • dest: 指定的有序集合
      • keys: 缓存名的集合,如: ['k1', 'k2', 'k3']
      • aggregate: SUM  MIN  MAX

import redis

pool = redis.ConnectionPool(decode_responses=True)
r = redis.Redis(connection_pool=pool)

r.zadd(name='library1', mapping={'book1_1': 1, 'book': 2, 'book1_3': 3})
r.zadd(name='library2', mapping={'book2_1': 1, 'book': 2, 'book2_3': 3})

r.zinterstore(dest='l_boos', keys=['library1', 'library2'])

print(r.zrange('l_boos', 0, -1, withscores=True, score_cast_func=int))  # [('book', 4)]

  • zunionstore(dest, keys, aggregate)

    • 将有序集合之间的并集存储在指定的有序集合中,如果指定的有序集合已存在,则会将其覆盖,如果遇到相同值不同分数,则按照aggregate进行操作

    • 参数:
      • dest: 指定的有序集合
      • keys: 缓存名的集合,如: ['k1', 'k2', 'k3']
      • aggregate: SUM  MIN  MAX

import redis

pool = redis.ConnectionPool(decode_responses=True)
r = redis.Redis(connection_pool=pool)

r.zadd(name='library1', mapping={'book1_1': 1, 'book': 2, 'book1_3': 3})
r.zadd(name='library2', mapping={'book2_1': 1, 'book': 2, 'book2_3': 3})

r.zunionstore(dest='l_boos', keys=['library1', 'library2'])

print(r.zrange('l_boos', 0, -1, withscores=True, score_cast_func=int))  # [('book1_1', 1), ('book2_1', 1), ('book1_3', 3), ('book2_3', 3), ('book', 4)]

  • zscan(name, cursor, match, count, score_cast_func)

    • 增量式迭代获取,对于数据大的数据非常有用,zscan可以实现分片的获取数据,并非一次性将数据全部获取完,从而防止内存被撑爆

    • 当有序集合中的成员数量过少的时候,zscan 是无效的

    • decode_responses 参数的问题和 get(name) 方法一样(这里就不做演示了)

    • 参数:
      • name: 缓存名
      • cursor: 游标(基于游标分批取获取数据)
      • match: 匹配指定key,默认None 表示所有的key
      • count: 每次分片最少获取个数,默认None表示采用redis的默认分片个数
      • score_cast_func: 对分数进行数据转换的函数,默认使用的函数是 float,可以修改为 int

    • 返回值:
      • 返回值有两个
      • 第一个: 游标 -> 当游标为0的时候表示数据以及获取完
      • 第二个: 获取到的值

    • 说明 zscan 的用法的写法

import redis

pool = redis.ConnectionPool(decode_responses=True)
r = redis.Redis(connection_pool=pool)

# 写入 1024 条数据
# for i in range(1024):
#     r.zadd('library', {
#         'book_%s' % i: i
#     })

cursor1, data1 = r.zscan('library', cursor=0, match=None, count=None, score_cast_func=int)
print(cursor1, data1)  # 64 [('book_1012', 1012), ('book_554', 554), ('book_532', 532), ('book_415', 415), ('book_335', 335), ('book_313', 313), ('book_162', 162), ('book_42', 42), ('book_41', 41), ('book_111', 111), ('book_121', 121)]
cursor2, data2 = r.zscan('library', cursor=cursor1, match=None, count=None, score_cast_func=int)
print(cursor2, data2)  # 160 [('book_323', 323), ('book_236', 236), ('book_876', 876), ('book_675', 675), ('book_625', 625), ('book_549', 549), ('book_359', 359), ('book_285', 285), ('book_143', 143), ('book_814', 814), ('book_345', 345), ('book_130', 130)]
cursor1, data1 = r.zscan('library', cursor=cursor2, match=None, count=None, score_cast_func=int)
print(cursor1, data1)  # 224 [('book_976', 976), ('book_905', 905), ('book_553', 553), ('book_284', 284), ('book_138', 138), ('book_6', 6), ('book_737', 737), ('book_445', 445), ('book_411', 411), ('book_139', 139)]

    • 实际应用写法

import redis

pool = redis.ConnectionPool(decode_responses=True)
r = redis.Redis(connection_pool=pool)

# 写入 1024 条数据
# for i in range(1024):
#     r.zadd('library', {
#         'book_%s' % i: i
#     })

cursor = 1

while cursor:
    cursor, data = r.zscan('library', cursor=cursor, match=None, count=None, score_cast_func=int)
    print(cursor, data)

  • zscan_iter(name, match, count, score_cast_func)

    • zscan_iter利用yield封装zscan创建的生成器,实现分批去redis中获取数据

    • decode_responses 参数的问题和 get(name) 方法一样(这里就不做演示了)

    • 参数:
      • name: 缓存名
      • match: 匹配指定key,默认None 表示所有的key
      • count: 每次分片最少获取个数,默认None表示采用redis的默认分片个数
      • score_cast_func: 对分数进行数据转换的函数,默认使用的函数是 float,可以修改为 int

import redis

pool = redis.ConnectionPool(decode_responses=True)
r = redis.Redis(connection_pool=pool)

# 写入 1024 条数据
# for i in range(1024):
#     r.zadd('library', {
#         'book_%s' % i: i
#     })

for i in r.zscan_iter('library'):
    print(i)

6. 其他常用方法

  • delete(*names)

    • 删除一个或多个已存在的任意数据类型缓存,不存在则会被忽略

    • 删除一个任意数据类型缓存

import redis

pool = redis.ConnectionPool(decode_responses=True)
r = redis.Redis(connection_pool=pool)

r.delete('info')

    • 删除多个数据类型缓存

      • 写法一

import redis

pool = redis.ConnectionPool(decode_responses=True)
r = redis.Redis(connection_pool=pool)

r.delete('info', 'str_data')

      • 写法二

import redis

pool = redis.ConnectionPool(decode_responses=True)
r = redis.Redis(connection_pool=pool)

names = ['info', 'str_data']
r.delete(*names)

    • 删除全部的数据类型缓存

import redis

pool = redis.ConnectionPool(decode_responses=True)
r = redis.Redis(connection_pool=pool)

r.delete(*r.keys())

  • flushall()

    • 清空所有缓存

import redis

pool = redis.ConnectionPool(decode_responses=True)
r = redis.Redis(connection_pool=pool)

r.flushall()

  • exists(name)

    • 检测缓存名是否存在

    • 返回值: 
      • 0 -> 不存在
      • 1 -> 存在

import redis

pool = redis.ConnectionPool(decode_responses=True)
r = redis.Redis(connection_pool=pool)

isHas = r.exists('info')

print(isHas)  # 1

  • keys(pattern)

    • 根据 pattern 参数获取缓存名(即: 缓存key),如果 pattern 不传值,默认获取所有缓存名(即: 缓存key)

    • decode_responses 参数的问题和 get(name) 方法一样(这里就不做演示了)

    • 参数:
      • pattern: 相当于一个简单的正则

import redis

pool = redis.ConnectionPool(decode_responses=True)
r = redis.Redis(connection_pool=pool)

# * -> 获取所有缓存名
# r.keys(pattern='*')
# 等价于
print(r.keys())  # ['hxllo', 'hbbbllo', 's_key3', 'hallo', 'hdddllo', 's_key2', 's_key1', 'hello']

# -----------------------------------------------

# xxx?xxx -> ? 0个或1个
print(r.keys(pattern='h?llo'))  # ['hxllo', 'hallo', 'hello']
print(r.keys(pattern='s_key?'))  # ['s_key3', 's_key2', 's_key1']

# -----------------------------------------------

# xxx*xxx -> * 多个
print(r.keys(pattern='h*llo'))  # ['hxllo', 'hbbbllo', 'hallo', 'hdddllo', 'hello']

# -----------------------------------------------

# xxx[]xxx -> 区域匹配
print(r.keys(pattern='h[ae]llo'))  # ['hallo', 'hello']

  • expire(name, time)

    • 给某一个缓存设置或修改超时时间 -> list, hash, set, sorted set 可以通过该方法设置超时时间

    • 参数:
      • name: 缓存名
      • time: 超时时间(单位: 秒)

import redis

pool = redis.ConnectionPool(decode_responses=True)
r = redis.Redis(connection_pool=pool)

r.hmset('info', {'username': 'Kevin', 'age': 18})

r.expire(name='info', time=10)

  • rename(src, dst)

    • 重命名缓存名

    • 参数:
      • src: 需要重命名的缓存名
      • dst: 新的缓存名

import redis

pool = redis.ConnectionPool(decode_responses=True)
r = redis.Redis(connection_pool=pool)

r.hmset('info', {'username': 'Kevin', 'age': 18})

r.rename(src='info', dst='user_info')

print(r.hgetall('info'))  # {}
print(r.hgetall('user_info'))  # {'age': '18', 'username': 'Kevin'}

  • move(name, db)

    • 将redis的某个值移动到指定的db下

    • 将当前数据库的 key 移动到给定的数据库 db 当中,select可以设定当前的数据库,如有需要请看select命令因为我们默认使用的数据库是db0,我们可以使用下面的命令键 2 移动到数据库 1 中去

r.move(2,1)

  • randomkey()

    • 随机获取一个缓存名

    • decode_responses 参数的问题和 get(name) 方法一样(这里就不做演示了)

import redis

pool = redis.ConnectionPool(decode_responses=True)
r = redis.Redis(connection_pool=pool)

redis_name = r.randomkey()

print(redis_name)  # user_info

  • type(name)

    • 获取指定缓存名所对应值的类型

import redis

pool = redis.ConnectionPool(decode_responses=True)
r = redis.Redis(connection_pool=pool)

r_type = r.type('user_info')

print(r_type)  # hash

  • scan(cursor, match, count)

    • 增量式迭代获取缓存名,对于数据大的数据非常有用,scan可以实现分片的获取数据,并非一次性将数据全部获取完,从而防止内存被撑爆

    • 当缓存中的缓存名数量过少的时候,scan 是无效的

    • decode_responses 参数的问题和 get(name) 方法一样(这里就不做演示了)

    • 参数:
      • cursor: 游标(基于游标分批取获取数据)
      • match: 匹配指定key,默认None 表示所有的key
      • count: 每次分片最少获取个数,默认None表示采用redis的默认分片个数

    • 返回值:
      • 返回值有两个
      • 第一个: 游标 -> 当游标为0的时候表示数据以及获取完
      • 第二个: 获取到的值

    • 说明 scan 的用法的写法

import redis

pool = redis.ConnectionPool(decode_responses=True)
r = redis.Redis(connection_pool=pool)

# 写入 1024 条数据
# for i in range(1024):
#     r.set('book_name%s' % i, 'book_%s' % i)

cursor1, data1 = r.scan(cursor=0, match=None, count=None)
print(cursor1, data1)  # 640 ['book_name633', 'book_name239', 'book_name180', 'book_name177', 'book_name464', 'book_name798', 'book_name193', 'book_name110', 'book_name972', 'book_name597']
cursor2, data2 = r.scan(cursor=cursor1, match=None, count=None)
print(cursor2, data2)  # 192 ['book_name694', 'book_name623', 'book_name305', 'book_name1014', 'book_name885', 'book_name808', 'book_name434', 'book_name10', 'book_name461', 'book_name454']
cursor1, data1 = r.scan(cursor=cursor2, match=None, count=None)
print(cursor1, data1)  # 672 ['book_name296', 'book_name322', 'book_name774', 'book_name721', 'book_name440', 'book_name674', 'book_name256', 'book_name204', 'book_name493', 'book_name18']

    • 实际应用写法

import redis

pool = redis.ConnectionPool(decode_responses=True)
r = redis.Redis(connection_pool=pool)

# 写入 1024 条数据
# for i in range(1024):
#     r.set('book_name%s' % i, 'book_%s' % i)

cursor = 1

while cursor:
    cursor, data = r.scan(cursor=cursor, match=None, count=None)
    print(cursor, data)

  • scan_iter(match=None, count=None)

    • scan_iter利用yield封装scan创建的生成器,实现分批去redis中获取数据

    • decode_responses 参数的问题和 get(name) 方法一样(这里就不做演示了)

    • 参数:
      • match: 匹配指定key,默认None 表示所有的key,可以和keys方法一样支持模糊查询
      • count: 每次分片最少获取个数,默认None表示采用redis的默认分片个数

import redis

pool = redis.ConnectionPool(decode_responses=True)
r = redis.Redis(connection_pool=pool)

# 写入 1024 条数据
# for i in range(1024):
#     r.set('book_name%s' % i, 'book_%s' % i)

# 获取所有缓存名
for i in r.scan_iter():
    print(i)

# -----------------------------------------------

# xxx?xxx -> ? 0个或1个

# for i in r.scan_iter(match='h?llo'):
# 等同于
for i in r.scan_iter('h?llo'):
    print(i)  # 'hxllo', 'hallo', 'hello'

# for i in r.scan_iter(match='s_key?'):
# 等同于
for i in r.scan_iter('s_key?'):
    print(i)  # 's_key3', 's_key2', 's_key1'

# -----------------------------------------------

# xxx*xxx -> * 多个

# for i in r.scan_iter(match='h*llo'):
# 等同于
for i in r.scan_iter('h*llo'):
    print(i)  # 'hxllo', 'hbbbllo', 'hallo', 'hdddllo', 'hello'

# -----------------------------------------------

# xxx[]xxx -> 区域匹配

# for i in r.scan_iter(match='h[ae]llo'):
# 等同于
for i in r.scan_iter('h[ae]llo'):
    print(i)  # 'hallo', 'hello'